﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using KinectCore.hwKinectComponents.Actions;
using xnv;

namespace KinectCore.hwKinectComponents
{
    /// <summary>
    /// An abstract class that contains the implementations required to make objects interact with the Kinect
    /// </summary>
    public class HWKinectComponent<T> : PointControl
    {
        #region Declaration of Variables Common to All HWKinect Components
        private string name;
        private int timeOut;

        private Broadcaster broadCaster;

        // Kinect Detectors
        private PushDetector pushDetector;
        private SteadyDetector steadyDetector;
        private SwipeDetector swipeDetector;
        private WaveDetector waveDetector;

        // Gesture Detection Action Dictionary
        private Dictionary<HWKinectGestures, hwKinectComponents.Actions.IHWKinectAction> gestureActions;

        // Timeout Timer
        private System.Timers.Timer _cancelTimer;
        private T component;

        #endregion

        //TODO: not sure what the value of the uint should be in base()
        /// <summary>
        /// Initilises the objects required for interaction with the Kinect
        /// </summary>
        /// <param name="pName">The name of the object</param>
        /// <param name="pTimeOut">The time(ms) before control is handed back up a level</param>
        public HWKinectComponent(String pName, int pTimeOut, T component)
            : base()
        {

            this.name = pName;
            this.timeOut = pTimeOut;
            this.broadCaster = new Broadcaster();
            this.component = component;

            gestureActions = new Dictionary<HWKinectGestures, Actions.IHWKinectAction>();
            
            OnUpdate += new UpdateHandler(HWKinectComponent_OnUpdate);
        }

        public T Component { get { return component; } }

        /// <summary>
        /// Broadcasts updates
        /// </summary>
        /// <param name="message">The message</param>
        void HWKinectComponent_OnUpdate(IntPtr message)
        {
            this.broadCaster.UpdateMessage(message);
        }

        #region Gesture Detections and Actions

        /// <summary>
        /// Activates the detection of push gestures
        /// </summary>
        /// <param name="pushAction">The action to be performed when a push gesture is detected</param>
        public void ActivatePushDetector(IHWKinectPushAction pushAction)
        {

            gestureActions.Add(HWKinectGestures.Push, pushAction);

            pushDetector = new PushDetector();
            pushDetector.Push += new PushDetector.PushHandler(pushDetector_Push);

        }

        /// <summary>
        /// Activates the detection of steady (hand) gestures
        /// </summary>
        /// <param name="steadyAction">The action to perform when a steady(hand) gesture is detected</param>
        public void ActivateSteadyDetector(IHWKinectSteadyAction steadyAction)
        {

            gestureActions.Add(HWKinectGestures.Steady, steadyAction);

            steadyDetector = new SteadyDetector();
            steadyDetector.Steady += new SteadyDetector.SteadyHandler(steadyDetector_Steady);
        }

        /// <summary>
        /// Activates the detection of swipe gestures
        /// </summary>
        /// <param name="swipeAction">The action to perform when a swipe gesture is detected</param>
        public void ActivateSwipeDetector(IHWKinectSwipeAction swipeAction)
        {
            gestureActions.Add(HWKinectGestures.Swipe, swipeAction);

            swipeDetector = new SwipeDetector();
            swipeDetector.GeneralSwipe += new SwipeDetector.GeneralSwipeHandler(swipeDetector_GeneralSwipe);
        }

        /// <summary>
        /// Activates the detection of wave gestures
        /// </summary>
        /// <param name="waveAction">The action to perform when a wave gesture is detected</param>
        public void ActivateWaveDetector(IHWKinectWaveAction waveAction)
        {
            gestureActions.Add(HWKinectGestures.Wave, waveAction);

            waveDetector = new WaveDetector();
            waveDetector.Wave += new WaveDetector.WaveHandler(waveDetector_Wave);
        }

        /// <summary>
        /// Code to execute when a push gesture is detected
        /// </summary>
        /// <param name="velocity">The velocity of the push</param>
        /// <param name="angle">The angle of the push</param>
        void pushDetector_Push(float velocity, float angle)
        {

            // Get the action to perform from the action dictionary
            IHWKinectPushAction pushAction = (IHWKinectPushAction)gestureActions[HWKinectGestures.Push];
            pushAction.DoAction(velocity, angle);

            if (pushAction.LeaveAfterAction && Leave != null)
            {
                Leave();
            }

        }

        /// <summary>
        /// Code to execute when a steady (hand) gesture is detected
        /// </summary>
        /// <param name="velocity">The velocity of the steady (hand) gesture??</param>
        void steadyDetector_Steady(float velocity)
        {

            // Get the action to perform from the action dictionary
            IHWKinectSteadyAction steadyAction = (IHWKinectSteadyAction)gestureActions[HWKinectGestures.Steady];
            steadyAction.DoAction(velocity);

            if (steadyAction.LeaveAfterAction && Leave != null)
            {
                Leave();
            }

        }

        /// <summary>
        /// Code to execute when a swipe gesture is detected
        /// </summary>
        /// <param name="selectionDirection">The direction of the swipe</param>
        /// <param name="velocity">The velocity of the swipe</param>
        /// <param name="angle">The angle of the swipe</param>
        void swipeDetector_GeneralSwipe(Direction dir, float velocity, float angle)
        {

            // Get the action to perform from the action dictionary
            IHWKinectSwipeAction swipeAction = (IHWKinectSwipeAction)gestureActions[HWKinectGestures.Swipe];
            swipeAction.DoAction(dir, velocity, angle);

            if (swipeAction.LeaveAfterAction && Leave != null)
            {
                Leave();
            }

        }

        /// <summary>
        /// Code to execute when a wave gesture is detected
        /// </summary>
        void waveDetector_Wave()
        {

            // Get the action to perform from the action dictionary
            IHWKinectWaveAction waveAction = (IHWKinectWaveAction)gestureActions[HWKinectGestures.Wave];
            waveAction.DoAction();

            if (waveAction.LeaveAfterAction && Leave != null)
            {
                Leave();
            }

        }

        #endregion

        //TODO: Comment the below
        #region Timeout Handlers

        /// <summary>
        /// Starts the timer
        /// </summary>
        public void StartTimer()
        {
            _cancelTimer = new System.Timers.Timer(timeOut);
            _cancelTimer.Elapsed += new System.Timers.ElapsedEventHandler(_cancelTimer_Elapsed);
            _cancelTimer.Start();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _cancelTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            _cancelTimer.Stop();
            this.Leave();
        }

        #endregion

        #region Leave Event
        public delegate void LeaveHandler();
        public event LeaveHandler Leave;
        #endregion

    }
}
